#ifndef trackreceiver
#define trackreceiver

#include <map>
#include <pthread.h>
#include "../party-protocol/packet.hpp"
#include "mixer.hpp"
#include "slab.hpp"

#define MAX_LATENCY (unsigned int)100 //max latency, in packets.
#define LATENCY_HISTORY_LENGTH 100

#define SOUNDSEGMENT_CONTENT_LENGTH 4096

struct readStatus{
    unsigned int index;
    int position;
    readStatus(){
        this->index=0;
        this->position=0;
    }
};

struct soundsegment_content_size{
    char content[SOUNDSEGMENT_CONTENT_LENGTH];
};

extern Slab<soundsegment_content_size> soundSegmentContentPool;
struct soundSegment{
    public:
    char* addr;
    unsigned int length;
    soundSegment(unsigned int length){
        this->addr=(char*)soundSegmentContentPool.alloc();
        this->length=length;
    };
    ~soundSegment(){
        soundSegmentContentPool.release((soundsegment_content_size*)this->addr);
    };
};

extern Slab<soundSegment> soundSegmentPool;
struct singleHostTrack{
    std::map<int,soundSegment*> allSegments;
    readStatus status;
    pthread_mutex_t lock;
    unsigned int last_receive_index;

    singleHostTrack(){
        this->status=readStatus();
        this->last_receive_index=0;
        this->lock=PTHREAD_MUTEX_INITIALIZER;
        this->allSegments[0]=new (soundSegmentPool.alloc()) soundSegment(0);
    };
    ~singleHostTrack(){
        for(auto segment=this->allSegments.begin();segment!=this->allSegments.end();){
            segment->second->~soundSegment();
            soundSegmentPool.release(segment->second);
            this->allSegments.erase(segment++);
        }
    };
    bool valid(){
        pthread_mutex_lock(&this->lock);
        bool result=this->last_receive_index>this->status.index;
        pthread_mutex_unlock(&this->lock);
        return result;
    }
    void readSound(char* readto_address, unsigned int length);
};
class Trackreceiver{
    public:
    std::map<uint32_t,singleHostTrack*> allHosts;
    Mixer<singleHostTrack> soundMixer;
    pthread_mutex_t lock;

    Trackreceiver();
    void receiveSound(Packet* packet);
    void readSound(char* readto_address, unsigned int length);
    bool ensure_exist();
    bool valid();
};

#endif
